/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package sma;

import jade.core.AID;
import jade.core.Agent;
import jade.domain.DFService;
import jade.domain.FIPAAgentManagement.DFAgentDescription;
import jade.domain.FIPAAgentManagement.FailureException;
import jade.domain.FIPAAgentManagement.NotUnderstoodException;
import jade.domain.FIPAAgentManagement.RefuseException;
import jade.domain.FIPAAgentManagement.ServiceDescription;
import jade.domain.FIPAException;
import jade.domain.FIPANames;
import jade.lang.acl.ACLMessage;
import jade.lang.acl.MessageTemplate;
import jade.lang.acl.UnreadableException;
import jade.proto.AchieveREInitiator;
import jade.proto.AchieveREResponder;
import java.io.IOException;
import sma.ontology.AuxInfo;
import sma.ontology.Cell;
import sma.ontology.InfoAgent;
import sma.ontology.InfoGame;

/**
 *
 * @author 
 */
public class HarvesterCoordinatorAgent extends Agent {
    private AuxInfo info;

    private AID harvesterAgent;
    private AID coordinatorAgent;
    
//    private sma.ontology.InfoGame game;

 
    public HarvesterCoordinatorAgent() {
    }

    /**
    * A message is shown in the log area of the GUI
    * @param str String to show
    */
    private void showMessage(String str) {
        System.out.println(getLocalName() + ": " + str);
    }
    
    /**
   * Agent setup method - called when it first come on-line. Configuration
   * of language to use, ontology and initialization of behaviours.
   */
  protected void setup() {

    /**** Very Important Line (VIL) *********/
    this.setEnabledO2ACommunication(true, 1);
    /****************************************/

    // Register the agent to the DF
    ServiceDescription sd1 = new ServiceDescription();
    sd1.setType(UtilsAgents.HARVESTERCOORDINATOR_AGENT);
    sd1.setName(getLocalName());
    sd1.setOwnership(UtilsAgents.OWNER);
    DFAgentDescription dfd = new DFAgentDescription();
    dfd.addServices(sd1);
    dfd.setName(getAID());
    try {
      DFService.register(this, dfd);
      showMessage("Registered to the DF");
    }
    catch (FIPAException e) {
      System.err.println(getLocalName() + " registration with DF " + "unsucceeded. Reason: " + e.getMessage());
      doDelete();
    }

    // search Coordinator Agent
//    ServiceDescription searchCriterion = new ServiceDescription();
//    searchCriterion.setType(UtilsAgents.COORDINATOR_AGENT);
//    this.coordinatorAgent = UtilsAgents.searchAgent(this, searchCriterion);
    
     // search Harvester Agent
//    searchCriterion.setType(UtilsAgents.HARVESTER_AGENT);
//    this.harvesterAgent = UtilsAgents.searchAgent(this, searchCriterion);
    // searchAgent is a blocking method, so we will obtain always a correct AID

   /**************************************************/
    ACLMessage requestInicial = new ACLMessage(ACLMessage.REQUEST);
    requestInicial.clearAllReceiver();
    requestInicial.addReceiver(this.coordinatorAgent);
    requestInicial.setProtocol(FIPANames.InteractionProtocol.FIPA_REQUEST);
    showMessage("d Message OK");
    try {
      requestInicial.setContent("Initial request d");
      showMessage("d Content OK" + requestInicial.getContent());
    } catch (Exception e) {
      e.printStackTrace();
    }

    //we add a behaviour that sends the message and waits for an answer
    //this.addBehaviour(new RequesterBehaviour(this, requestInicial));
    // setup finished. When we receive the last inform, the agent itself will add
    // a behaviour to send/receive actions
    
   MessageTemplate mt = MessageTemplate.MatchProtocol(UtilsAgents.PROTOCOL_TURN);
   this.addBehaviour(new QueriesReceiver(this, mt));

  } //endof setup
  /*************************************************************************/

  /**
    * <p><B>Title:</b> IA2-SMA</p>
    * <p><b>Description:</b> Practical exercise 2011-12. Recycle swarm.</p>
    * This class lets send the REQUESTs for any agent. Concretely it is used in the 
    * initialization of the game. The Coordinator Agent sends a REQUEST for the information
    * of the game (instance of <code>AuxInfo</code> containing parameters, coordenates of 
    * the agents and the recycling centers and visual range of each agent). The Central Agent
    * sends an AGREE and then it informs of this information which is stored by the Coordinator
    * Agent. The info is processed by another behaviour that we add after the INFORM has been 
    * processed.
    * <p><b>Copyright:</b> Copyright (c) 2011</p>
    * <p><b>Company:</b> Universitat Rovira i Virgili (<a
    * href="http://www.urv.cat">URV</a>)</p>
    * @author David Isern and Joan Albert López
    * @see sma.ontology.Cell
    * @see sma.ontology.InfoGame
   */
class RequesterBehaviour extends AchieveREInitiator {
	  
	private ACLMessage msgSent = null;
    
    public RequesterBehaviour(Agent myAgent, ACLMessage requestMsg) {
      super(myAgent, requestMsg);
      showMessage("AchieveREInitiator starts...");
      msgSent = requestMsg;
    }

    /**
     * Handle AGREE messages
     * @param msg Message to handle
     */
        @Override
    protected void handleAgree(ACLMessage msg) {
      showMessage("AGREE received from "+ ( (AID)msg.getSender()).getLocalName());
    }

    /**
     * Handle INFORM messages
     * @param msg Message
     */
        @Override
    protected void handleInform(ACLMessage msg) {
    	showMessage("INFORM received from "+ ( (AID)msg.getSender()).getLocalName()+" ... [OK]");
        try {
          info = (AuxInfo)msg.getContentObject();
          if (info instanceof AuxInfo) { 
            showMessage("Info recieved: :-) ");
            showMessage(info.toString());
          }
        } catch (Exception e) {
          showMessage("Incorrect content: "+e.toString());
        }
    }

    /**
     * Handle NOT-UNDERSTOOD messages
     * @param msg Message
     */
        @Override
    protected void handleNotUnderstood(ACLMessage msg) {
      showMessage("This message NOT UNDERSTOOD. \n");
    }
        
    /**
     * Handle FAILURE messages
     * @param msg Message
     */
        @Override
    protected void handleFailure(ACLMessage msg) {
      showMessage("The action has failed.");

    } //End of handleFailure

    /**
     * Handle REFUSE messages
     * @param msg Message
     */
        @Override
    protected void handleRefuse(ACLMessage msg) {
      showMessage("Action refused.");
    }
  } //Endof class RequesterBehaviour
class QueriesReceiver extends AchieveREResponder {

        /* (non-Javadoc)
         * @see jade.proto.AchieveREResponder#prepareResponse(jade.lang.acl.ACLMessage)
         */
        @Override
        protected ACLMessage prepareResponse(ACLMessage arg0) throws NotUnderstoodException, RefuseException {
                ACLMessage response = arg0.createReply();

                try {
                        if (arg0.getContentObject() instanceof AuxInfo) {
                                response.setPerformative(ACLMessage.AGREE);
                                info = (AuxInfo) arg0.getContentObject();
                                showMessage("New turn " + info.toString());

        //			manageScouts(this.myAgent);
                        } else if (arg0.getPerformative() == ACLMessage.AGREE) {
                                response = null;
                        } else {
                                throw new NotUnderstoodException("Not the expected object type");
                        }
                } catch (UnreadableException e) {
                        response.setPerformative(ACLMessage.FAILURE);
                }
                 showMessage("Get information");
                return response;
        }

        /* (non-Javadoc)
         * @see jade.proto.AchieveREResponder#prepareResultNotification(jade.lang.acl.ACLMessage, jade.lang.acl.ACLMessage)
         */
        @Override
        protected ACLMessage prepareResultNotification(ACLMessage arg0, ACLMessage arg1) throws FailureException {
                return null;
        }

        /* (non-Javadoc)
         * @see jade.proto.AchieveREResponder#handleRequest(jade.lang.acl.ACLMessage)
         */
        @Override
        protected ACLMessage handleRequest(ACLMessage arg0) throws NotUnderstoodException, RefuseException {
                try {
                        Object objectReceived = arg0.getContentObject();
                        if (objectReceived instanceof AuxInfo) {
                                // Is the coordinator informing of a new turn
                                info = (AuxInfo) objectReceived;
                                showMessage("New turn received from coordinator: " + info.toString());

                                // Find all my agents and send them the new turn
                                ACLMessage message = new ACLMessage(ACLMessage.REQUEST);
                                for (int x = 0; x < info.getMap().length; x++) {
                                        for (int y = 0; y < info.getMap()[x].length; y++) {
                                                Cell c = info.getCell(x, y);
                                                if (c!=null)
                                                        if (c.isThereAnAgent()) {
                                                                InfoAgent a = c.getAgent();
                                                                if (a.getAgent().equals("H")) {
                                                                        message.addReceiver(a.getAID());
                                                                }
                                                        }
                                        }
                                }
                                
                                message.setProtocol(UtilsAgents.PROTOCOL_TURN);
                                message.setSender(this.myAgent.getAID());
                                message.setContentObject(info);//getInfo() added <---- :-D
//                                this.myAgent.send(message);
                                this.myAgent.addBehaviour(new MessageSender(this.myAgent, message));

                        }

                } catch (UnreadableException e) {
                        showMessage("Received an Object that cannot be understood");
                } catch (IOException e) {
                        e.printStackTrace();
                } catch (Exception e) {
                        e.printStackTrace();
                }
                showMessage("Sent information");
                return super.handleRequest(arg0);
        }

        public QueriesReceiver(Agent arg0, MessageTemplate arg1) {
                super(arg0, arg1);
        }
}
class MessageSender extends AchieveREInitiator
  {

	/**
	 * 
	 */

	public MessageSender(Agent arg0, ACLMessage arg1) {
		super(arg0, arg1);
		// TODO Auto-generated constructor stub
	}
	  
  }

  /*************************************************************************/
}//Endof HarvesterCoordinatorAgent